/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package db.gui;

import db.genomemap.RDBSettings;

import javautil.swing.components.ProgressSupport;
import javautil.swing.components.ProgressSupportable;

import java.sql.*;
import java.util.Collection;
import java.util.HashSet;

/**
 * Class description
 *
 * @version        Enter version here..., 12/11/23
 * @author         Susanta Tewari
 */
public class RDBConnection implements ProgressSupportable {

    /** Field description */
    private ProgressSupport progressSupport = null;

    /** Field description */
    private Connection connection = null;

    /** Field description */
    private RDBConnectionModel connectionModel = null;

    /**
     * Constructs ...
     */
    public RDBConnection() {
        progressSupport = new ProgressSupport(this);
    }

    /**
     * Constructs ...
     *
     * @param connectionModel description
     */
    public RDBConnection(RDBConnectionModel connectionModel) {

        progressSupport      = new ProgressSupport(this);
        this.connectionModel = connectionModel;
    }

    public ProgressSupport getProgressSupport() {
        return progressSupport;
    }

    public boolean isSchemaExists() {

        if (connectionModel == null) return false;

        String schema = connectionModel.getSchema();

        if ((schema == null) || (getStatement() == null)) return false;

        boolean exists = true;

        try {
            getStatement().execute("USE " + schema + ";");
        } catch (Exception e) {

            e.printStackTrace();

            exists = false;

        } finally {
            return exists;
        }
    }

    /**
     * this one assumes that schema is available. runs on EDT thread
     * as it`s not long
     */
    public boolean checkSchemaCompatibility() {

        Statement stmt = getStatement();

        if (stmt == null) {

            progressSupport.setStatusInfo("Connection failed ! Cannot check schema compatibility.");

            return false;
        }


        // show the progress bar
        progressSupport.setShowProgress(true);
        progressSupport.sleep(2);
        progressSupport.setProgress(20);


        // @todo: implement a detailed checking later
        // make a short checking... check if all the tables are present
        // get the collection of all must-be present table names from RDBSettings
        ResultSet rs                           = null;
        Collection<String> tableNamesFound     = new HashSet<>();
        Collection<String> tableNamesTobeFound = RDBSettings.getTableNames();
        boolean testPassed                     = true;

        try {


            // set the schema
            stmt.execute("USE " + connectionModel.getSchema() + ";");

            rs = stmt.executeQuery("SHOW TABLES;");

            while (rs.next()) {

                tableNamesFound.add(rs.getString(1));
            }

            progressSupport.setProgress(60);

            if (!tableNamesTobeFound.equals(tableNamesFound)) testPassed = false;

            System.out.println("tables to be found: ");
            System.out.println(tableNamesTobeFound);
            System.out.println("tables found: ");
            System.out.println(tableNamesFound);
            progressSupport.setProgress(100);
        } catch (SQLException ex) {

            ex.printStackTrace();

            testPassed = false;

        } finally {


            // close the progress bar
            if (testPassed)
                progressSupport.setStatusInfo("Schema " + connectionModel.getSchema()
                                              + " is Compatible");
            else
                progressSupport.setStatusInfo("Schema " + connectionModel.getSchema()
                                              + " is NOT Compatible");

            progressSupport.sleep(2);
            progressSupport.setShowProgress(false);

            return testPassed;
        }
    }

    public void close() throws SQLException {
        if (connection != null) connection.close();
    }

    /**
     * a convinience method for testing connection
     */
    public static boolean testConnection(String serverHost, String port, String userName,
            String password, String schema) {

        boolean connected = true;

        try {

            Class.forName("com.mysql.jdbc.Driver");

            String hostName = "jdbc:mysql://" + serverHost + ":" + port + "/mysql";
            Connection con  = DriverManager.getConnection(hostName, userName, password);
            Statement stmt  = con.createStatement();

            stmt.execute("USE " + schema + ";");

        } catch (ClassNotFoundException | SQLException e) {

            e.printStackTrace();

            connected = false;

        } finally {

            System.out.println("connected: " + connected);

            return connected;
        }
    }

    public boolean connect() {

        if (connectionModel == null) {


            // load the default model if available
            connectionModel = RDBSettings.load().getDefaultConnectionModel();

            if (connectionModel == null) return false;
        }

        String driver   = connectionModel.getDriver();
        String host     = connectionModel.getHostName();
        String userName = connectionModel.getUserName();
        String password = connectionModel.getPassword();

        if ((driver == null) || (host == null) || (userName == null) || (password == null))
            return false;


        // Create a Connection
        boolean connected = true;

        try {

            Class.forName(driver);

            connection = DriverManager.getConnection(host, userName, password);


            // stmt = con.createStatement();

        } catch (ClassNotFoundException | SQLException e) {

            e.printStackTrace();

            connected = false;

        } finally {
            return connected;
        }
    }

    public RDBConnectionModel getConnectionModel() {
        return connectionModel;
    }

    public void setConnectionModel(RDBConnectionModel connectionModel) {
        this.connectionModel = connectionModel;
    }

    public Connection getConnection() {
        return connection;
    }

    /**
     * returns statement for a particular schema, for any problem return <CODE>null</CODE>
     */
    public Statement getStatement() {

        if (connection == null) {


            // create a connection
            if (!connect()) return null;
        }

        Statement statement = null;

        try {

            statement = connection.createStatement();

            statement.execute("USE " + connectionModel.getSchema() + ";");

        } catch (SQLException ex) {

            ex.printStackTrace();

            statement = null;

        } finally {
            return statement;
        }
    }
}
